
#include "FontDefinition.h"
#include "ConfigDialog.h"
#include "StringUtil.h"

#include "wx/dir.h"
#include "wx/file.h"

#include "ft2build.h"
#include FT_FREETYPE_H

#include <vector>

// Instantiate the instance
FontMap* FontMap::mInstance = 0;

////////////////////////////////////////////////////////////////////////////////
// FontItem
////////////////////////////////////////////////////////////////////////////////

//Constructor
FontMap::FontItem::FontItem( const StringUtil::String& fontName )
    : mFamilyName( fontName )
{
    mFileNames.resize( STYLE_COUNT );
    for ( int i = 0; i < STYLE_COUNT; i++ )
        mFileNames[ i ] = "";
}

//GetFamilyName
StringUtil::String FontMap::FontItem::GetFamilyName() const
{
    return mFamilyName;
}

//SetFileName
bool FontMap::FontItem::SetFontFile( const StringUtil::String& fileName, bool isBold, bool isItalic, bool replaceIfPresent )
{
    // Get the index for the font file:
    FONT_STYLE styleIndex = REGULAR;
    if ( isBold && isItalic )
        styleIndex = BOLD_ITALIC;
    else if ( isBold )
        styleIndex = BOLD;
    else if ( isItalic )
        styleIndex = ITALIC;

    // If the file name is already set for this style, then do nothing (we should be fine.)
    // Otherwise, set the file name.
    if ( replaceIfPresent || ( mFileNames[ styleIndex ].length() == 0 ) )
        mFileNames[ styleIndex ] = fileName;

    return true;
}

//GetFontFile
StringUtil::String FontMap::FontItem::GetFontFile( bool isBold, bool isItalic ) const
{
    // Get the index for the font file:
    FONT_STYLE styleIndex = REGULAR;
    if ( isBold && isItalic )
        styleIndex = BOLD_ITALIC;
    else if ( isBold )
        styleIndex = BOLD;
    else if ( isItalic )
        styleIndex = ITALIC;

    // Check the font file.  If the string is empty, try the next style.  If
    // we've exhausted all styles, then bail out.
    FONT_STYLE initialStyle = styleIndex;
    StringUtil::String fileName = "";
    do
    {
        fileName = mFileNames[ styleIndex ];
        styleIndex = FONT_STYLE( ( styleIndex + 1 ) % STYLE_COUNT );
    } while ( fileName.length() == 0 && styleIndex != initialStyle );

    return fileName;
}

////////////////////////////////////////////////////////////////////////////////
// FontMap
////////////////////////////////////////////////////////////////////////////////

//Constructor
FontMap::FontMap()
{
    // Enumerate the available fonts:
    ConfigSettings settings = ConfigSettings::GetInstance();
    wxDir dirEnum( settings.mFontDirectory.c_str() );
    std::vector< StringUtil::String > fileNames;
    if ( dirEnum.IsOpened() )
    {
        wxString curFilename;
        bool cont = dirEnum.GetFirst( &curFilename, wxEmptyString );
        while ( cont )
        {
            StringUtil::String fullFileName = StringUtil::String( dirEnum.GetName().ToAscii() ) + "/" + StringUtil::String( curFilename.c_str() );
            if ( wxFile::Exists( fullFileName.c_str() ) )
                fileNames.push_back( fullFileName );
            cont = dirEnum.GetNext( &curFilename );
        }
    }

    // Go through the array of font files and use FreeType to extract the face
    // name for each font.
    FT_Library fontLib;
    FT_Error error = FT_Init_FreeType( &fontLib );
    if ( !error )
    {
        FT_Face face;
        std::vector< StringUtil::String >::const_iterator iter = fileNames.begin();
        for ( iter; iter != fileNames.end(); iter++ )
        {
            error = FT_New_Face( fontLib, iter->c_str(), 0, &face );
            if ( !error && face )
            {
                // Examine the style name to determine where this file should be placed...
                bool isBold = false, isItalic = false;
                StringUtil::String styleName = face->style_name;
                StringUtil::ToLower( styleName );
                if ( StringUtil::Find( styleName, "bold" ) >= 0 )
                    isBold = true;
                if ( StringUtil::Find( styleName, "italic" ) >= 0 )
                    isItalic = true;

                AddFileName( face->family_name, *iter, isBold, isItalic );

//                mFontMap[ face->family_name ] = *iter;
                FT_Done_Face( face );
                //mFontName->Append( face->family_name );
            }
        }
    }
}

FontMap::~FontMap()
{
    delete FontMap::mInstance;
}

//GetInstance
FontMap& FontMap::GetInstance()
{
    if ( !mInstance )
        mInstance = new FontMap();
    assert( mInstance );
    return *mInstance;
}

/** Get a pointer to the configuration settings */
FontMap* FontMap::GetInstancePtr()
{
    if ( !mInstance )
        mInstance = new FontMap();
    return mInstance;
}

//Begin
FontMap::Iterator FontMap::Begin()
{
    return mFontMap.begin();
}

//Begin
FontMap::ConstIterator FontMap::Begin() const
{
    return mFontMap.begin();
}

//End
FontMap::Iterator FontMap::End()
{
    return mFontMap.end();
}

//End
FontMap::ConstIterator FontMap::End() const
{
    return mFontMap.end();
}

//Count
size_t FontMap::Count() const
{
    return mFontMap.size();
}

//Find
FontMap::Iterator FontMap::Find( const StringUtil::String& key )
{
    return mFontMap.find( key );
}

//Find
FontMap::ConstIterator FontMap::Find( const StringUtil::String& key ) const
{
    return mFontMap.find( key );
}

//GetFileName
StringUtil::String FontMap::GetFileName( const StringUtil::String& fontName, bool isBold, bool isItalic ) const
{
    ConstIterator iter = mFontMap.find( fontName );
    if ( iter != mFontMap.end() )
        return iter->second.GetFontFile( isBold, isItalic );
    return "";
}

//AddFileName
bool FontMap::AddFileName( const StringUtil::String& fontName, const StringUtil::String& fileName, bool isBold, bool isItalic )
{
    // Attempt to locate the font:
    Iterator iter = mFontMap.find( fontName );

    // If the font doesn't exist, add a new FontItem to the map
    if ( iter == mFontMap.end() )
    {
        FontItem item( fontName );
        item.SetFontFile( fileName, isBold, isItalic );
        mFontMap[ fontName ] = item;
    }
    else
    {
        iter->second.SetFontFile( fileName, isBold, isItalic );
    }

    return true;
}
